use crate::error::AppError;
use crate::models::user::User;
use crate::utils::jwt::{DecodingKey, EncodingKey};
use crate::AppConfig;
use axum::response::IntoResponse;
use chrono::{DateTime, Local, TimeZone};
use dashmap::DashMap;
use serde::{de, ser, Deserialize, Serialize};
use sqlx::MySqlPool;
use std::fmt;
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use tokio::sync::broadcast;

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "event")]
pub enum AppEvent {
    NewChat,
    AddToChat,
    RemoveFromChat,
    NewMessage { data: String },
}

pub type UserMap = Arc<DashMap<u64, broadcast::Sender<Arc<AppEvent>>>>;

#[derive(Clone)]
pub struct AppState {
    pub inner: AppConfig,
    pub dk: DecodingKey,
    pub ek: EncodingKey,
    pub pool: MySqlPool,
    pub user: Arc<Mutex<Option<User>>>,
    pub users: UserMap,
}

impl AppState {
    pub async fn try_new(config: AppConfig) -> Result<Self, AppError> {
        let dk = DecodingKey::load(&config.auth.pk)?;
        let ek = EncodingKey::load(&config.auth.sk)?;
        let pool = MySqlPool::connect(&config.server.db_url).await?;
        Ok(AppState {
            inner: config,
            dk,
            ek,
            pool,
            user: Arc::new(Mutex::new(None)),
            users: Arc::new(DashMap::new()),
        })
    }
}

impl Deref for AppState {
    type Target = AppConfig;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl fmt::Debug for AppState {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("AppStateInner")
            .field("inner", &self.inner)
            .finish()
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Response<T> {
    pub status: u16,
    pub body: T,
    pub message: String,
}

impl<T> Response<T>
where
    T: serde::Serialize,
{
    pub fn new(status: u16, body: T, message: String) -> Self {
        Self {
            status,
            body,
            message,
        }
    }

    pub fn new_without_body(status: u16, body: T, message: String) -> Self {
        Self {
            status,
            body,
            message,
        }
    }
    pub fn ok(body: T) -> Self {
        Self::new(200, body, "success".to_string())
    }
    pub fn fail(status: u16, messages: String, body: T) -> Self {
        Self::new_without_body(status, body, messages)
    }
    pub fn bad_request(body: T, message: String) -> Self {
        Self::new(400, body, message)
    }
    pub fn unauthorized(body: T, message: String) -> Self {
        Self::new(401, body, message)
    }
    pub fn forbidden(body: T, message: String) -> Self {
        Self::new(403, body, message)
    }
    pub fn not_found(body: T, message: String) -> Self {
        Self::new(404, body, message)
    }
    pub fn internal_server_error(body: T, message: String) -> Self {
        Self::new(500, body, message)
    }
}

impl<T> IntoResponse for Response<T>
where
    T: serde::Serialize,
{
    fn into_response(self) -> axum::response::Response {
        serde_json::to_string(&self).unwrap().into_response()
    }
}

// 自定义序列化函数
pub fn serialize<S>(dt: &DateTime<Local>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: ser::Serializer,
{
    const FORMAT: &str = "%Y-%m-%d %H:%M:%S";
    serializer.serialize_str(&dt.format(FORMAT).to_string())
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Local>, D::Error>
where
    D: de::Deserializer<'de>,
{
    use chrono::{DateTime, Local, NaiveDateTime};

    let s = String::deserialize(deserializer)?;

    // 尝试解析为带有时区的字符串
    if let Ok(dt) =
        DateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S%.f %z").map(|dt| dt.with_timezone(&Local))
    {
        return Ok(dt);
    }

    if let Ok(dt) =
        DateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S %z").map(|dt| dt.with_timezone(&Local))
    {
        return Ok(dt);
    }

    // 尝试解析为无时区的字符串，并假设为本地时间
    if let Ok(dt) = NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S%.f") {
        return match Local.from_local_datetime(&dt).single() {
            Some(dt) => Ok(dt),
            None => Err(de::Error::custom(format!("Ambiguous time: {s}"))),
        };
    }

    if let Ok(dt) = NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S") {
        return match Local.from_local_datetime(&dt).single() {
            Some(dt) => Ok(dt),
            None => Err(de::Error::custom(format!("Ambiguous time: {s}"))),
        };
    }

    Err(de::Error::custom(format!(
        "Failed to parse '{s}' as local datetime"
    )))
}

#[derive(Debug)]
pub enum SortDirection {
    Ascending,
    Descending,
}

// 排序字段结构
#[derive(Debug)]
pub struct SortingField {
    pub name: String,
    pub direction: SortDirection,
}

#[derive(Debug, Serialize, Default)]
pub struct PaginatedResponse<T> {
    pub items: Vec<T>,
    pub current_page: i32,
    pub per_page: i32,
    pub total_items: i64,
    pub total_pages: i32,
}

// 解析排序字符串
pub fn parse_sort_fields(sort_str: Option<&str>) -> Vec<SortingField> {
    // 安全字段白名单
    const SAFE_FIELDS: &[&str] = &["id", "name", "created_at"];

    let mut fields = vec![];

    if let Some(sort_str) = sort_str {
        for field in sort_str.split(',') {
            let (name, direction) = match field.strip_prefix('-') {
                Some(n) => (n, SortDirection::Descending),
                None => (field, SortDirection::Ascending),
            };

            // 使用白名单验证字段名
            if SAFE_FIELDS.contains(&name) {
                fields.push(SortingField {
                    name: name.to_string(),
                    direction,
                });
            }
        }
    }

    // 确保至少有一个排序字段
    if fields.is_empty() {
        fields.push(SortingField {
            name: "id".to_string(),
            direction: SortDirection::Ascending,
        });
    }

    fields
}
